// useFileTreeStore
import { defineStore } from "pinia";
import { IFileTreeItem } from "../interface/FileTree";
import WebContainerAPI from "../class/WebContainerAPI";

type TPromiseResult = Promise<IFileTreeItem[] | undefined>;

/**
 * 【注意】虽然页面 el-tree 的数据源定义在这里，
 *  但是能够执行 新建、删除、重命名的根源是 webContainer 提供的能力，
 *  因此，这里的数据源，需要依靠 webContainer 的 fileTree 数据源来更新
 *  提供 render 方法，主动调用则实现更新操作
 *  更新了数据，页面也会刷新，还需要处理页面状态保留的问题
 */

export const useFileTreeStore = defineStore("fileTreeStore", {
  state: () => ({
    fileTreeData: <IFileTreeItem[]>[],
  }),
  actions: {
    // 渲染文件树列表
    async render() {
      // 还要进行解析，因为 webContainer 的数据源是 FileSystemTree 的，而 el-tree 需要嵌套的
      const data = <IFileTreeItem[]>await this.readAsFileTreeData();
      this.fileTreeData = sort(data);
    },

    /**
     * 将 File System Tree转成 Element Plus El-Tree 数据结构
     */
    async readAsFileTreeData(): TPromiseResult {
      // 内部函数实现递归
      const readFileTree = async (root: string): TPromiseResult => {
        const result = <IFileTreeItem[]>[];
        const files = await WebContainerAPI.readDir(root);
        if (!files) return result;

        // 遍历读取的目录 for...of
        for (const item of files) {
          const label = item.name;
          const type = item.isFile() ? "File" : "Folder";
          /**
           * 每一个数据项 都拥有唯一的路径，不然会报错
           *  这里创建的每一项数据项，都会更新 id = path 操作
           *  请确保更新后的ID 保持与 path 一致，否则会报错
           *  /src
           *  /index.js
           *  /src/ttt.ts
           */
          const path = `${root}/${item.name}`;
          if (item.isDirectory()) {
            const children = await readFileTree(path);
            result.push({ id: path, label, type, children });
          } else result.push({ id: path, label, type });
        }

        return result;
      };

      // 启动读取 传入空相当于 读取 根路径 / 但是不能传入/ 因为传入后，解析时的 `${root}/${item.name}` 会变成 //src
      return await readFileTree("");
    },
  },
});

/**
 * 辅助函数 sort
 */
function sort(arr: IFileTreeItem[]): IFileTreeItem[] {
  const data = JSON.parse(JSON.stringify(arr));
  return data.sort((a: IFileTreeItem, b: IFileTreeItem) => {
    // 先排序文件夹，再排序文件
    if (a.type === "Folder" && b.type === "File") return -1;
    else if (a.label > b.label) return 1;
    else return -1;
  });
}
